package net.takela.common.utils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * description here
 *
 */
public class Lists {

    private Lists() {}

    public static <S, T> List<T> transform(List<S> list, Function<S, T> fn) {
        return list.stream().map(fn).collect(Collectors.toList());
    }

    public static <S, T> List<T> nonNull(List<S> list, Function<S, T> fn) {
        return list.stream().map(fn).filter(Objects::nonNull).collect(Collectors.toList());
    }

    public static <S, T> List<T> distinct(List<S> list, Function<S, T> fn) {
        return list.stream().map(fn).filter(Objects::nonNull).distinct().collect(Collectors.toList());
    }
    /**
     * 
     */
    public static <T> int size(List<T> list) {
        return list == null ? 0 : list.size();
    }
    /**
     * 
     */
    public static <T> String join(Collection<T> coll, String delimiter) {
        return coll.stream().map(String::valueOf).collect(Collectors.joining(delimiter));
    }

    public static <T, R> String join(Collection<T> coll, Function<T, R> mapper, String delimiter) {
        return coll.stream().map(mapper).map(String::valueOf).collect(Collectors.joining(delimiter));
    }
    /**
     * 
     */
    public static <T> List<T> filter(Collection<T> collection, Predicate<? super T> predicate) {
        return collection.stream().filter(predicate).collect(Collectors.toList());
    }
    /**
     * 
     */
    public static <T> List<T> copy(T t, int num) {
        return IntStream.range(0, num).mapToObj(i -> t).collect(Collectors.toList());
    }

    public static <T> Map<T, Long> counting(List<T> list) {
        return list.stream().collect(Collectors.groupingBy(e -> e, Collectors.counting()));
    }
    /**
     * 
     */
    public static <T> List<T> ifNull(List<T> list) {
        return Optional.ofNullable(list).orElse(new ArrayList<>());
    }
}
